home *** CD-ROM | disk | FTP | other *** search
/ Chip 2007 January, February, March & April / Chip-Cover-CD-2007-02.iso / Pakiet bezpieczenstwa / mini Pentoo LiveCD 2006.1 / mpentoo-2006.1.iso / livecd.squashfs / usr / share / gtk-2.0 / demo / changedisplay.c < prev    next >
Encoding:
C/C++ Source or Header  |  2006-04-25  |  17.5 KB  |  628 lines

  1. /* Change Display
  2.  * 
  3.  * Demonstrates migrating a window between different displays and
  4.  * screens. A display is a mouse and keyboard with some number of
  5.  * associated monitors. A screen is a set of monitors grouped
  6.  * into a single physical work area. The neat thing about having
  7.  * multiple displays is that they can be on a completely separate
  8.  * computers, as long as there is a network connection to the
  9.  * computer where the application is running.
  10.  *
  11.  * Only some of the windowing systems where GTK+ runs have the
  12.  * concept of multiple displays and screens. (The X Window System
  13.  * is the main example.) Other windowing systems can only
  14.  * handle one keyboard and mouse, and combine all monitors into
  15.  * a single screen.
  16.  *
  17.  * This is a moderately complex example, and demonstrates:
  18.  *
  19.  *  - Tracking the currently open displays and screens
  20.  *
  21.  *  - Changing the screen for a window
  22.  *
  23.  *  - Letting the user choose a window by clicking on it
  24.  * 
  25.  *  - Using GtkListStore and GtkTreeView
  26.  *
  27.  *  - Using GtkDialog
  28.  */
  29. #include <string.h>
  30. #include <gtk/gtk.h>
  31. #include "demo-common.h"
  32.  
  33. /* The ChangeDisplayInfo structure corresponds to a toplevel window and
  34.  * holds pointers to widgets inside the toplevel window along with other
  35.  * information about the contents of the window.
  36.  * This is a common organizational structure in real applications.
  37.  */
  38. typedef struct _ChangeDisplayInfo ChangeDisplayInfo;
  39.  
  40. struct _ChangeDisplayInfo
  41. {
  42.   GtkWidget *window;
  43.   GtkSizeGroup *size_group;
  44.  
  45.   GtkTreeModel *display_model;
  46.   GtkTreeModel *screen_model;
  47.   GtkTreeSelection *screen_selection;
  48.   
  49.   GdkDisplay *current_display;
  50.   GdkScreen *current_screen;
  51. };
  52.  
  53. /* These enumerations provide symbolic names for the columns
  54.  * in the two GtkListStore models.
  55.  */
  56. enum
  57. {
  58.   DISPLAY_COLUMN_NAME,
  59.   DISPLAY_COLUMN_DISPLAY,
  60.   DISPLAY_NUM_COLUMNS
  61. };
  62.  
  63. enum
  64. {
  65.   SCREEN_COLUMN_NUMBER,
  66.   SCREEN_COLUMN_SCREEN,
  67.   SCREEN_NUM_COLUMNS
  68. };
  69.  
  70. /* Finds the toplevel window under the mouse pointer, if any.
  71.  */
  72. static GtkWidget *
  73. find_toplevel_at_pointer (GdkDisplay *display)
  74. {
  75.   GdkWindow *pointer_window;
  76.   GtkWidget *widget = NULL;
  77.  
  78.   pointer_window = gdk_display_get_window_at_pointer (display, NULL, NULL);
  79.  
  80.   /* The user data field of a GdkWindow is used to store a pointer
  81.    * to the widget that created it.
  82.    */
  83.   if (pointer_window)
  84.     gdk_window_get_user_data (pointer_window, (gpointer*) &widget);
  85.  
  86.   return widget ? gtk_widget_get_toplevel (widget) : NULL;
  87. }
  88.  
  89. static gboolean
  90. button_release_event_cb (GtkWidget       *widget,
  91.              GdkEventButton  *event,
  92.              gboolean        *clicked)
  93. {
  94.   *clicked = TRUE;
  95.   return TRUE;
  96. }
  97.  
  98. /* Asks the user to click on a window, then waits for them click
  99.  * the mouse. When the mouse is released, returns the toplevel
  100.  * window under the pointer, or NULL, if there is none.
  101.  */
  102. static GtkWidget *
  103. query_for_toplevel (GdkScreen  *screen,
  104.             const char *prompt)
  105. {
  106.   GdkDisplay *display = gdk_screen_get_display (screen);
  107.   GtkWidget *popup, *label, *frame;
  108.   GdkCursor *cursor;
  109.   GtkWidget *toplevel = NULL;
  110.   
  111.   popup = gtk_window_new (GTK_WINDOW_POPUP);
  112.   gtk_window_set_screen (GTK_WINDOW (popup), screen);
  113.   gtk_window_set_modal (GTK_WINDOW (popup), TRUE);
  114.   gtk_window_set_position (GTK_WINDOW (popup), GTK_WIN_POS_CENTER);
  115.   
  116.   frame = gtk_frame_new (NULL);
  117.   gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_OUT);
  118.   gtk_container_add (GTK_CONTAINER (popup), frame);
  119.   
  120.   label = gtk_label_new (prompt);
  121.   gtk_misc_set_padding (GTK_MISC (label), 10, 10);
  122.   gtk_container_add (GTK_CONTAINER (frame), label);
  123.   
  124.   gtk_widget_show_all (popup);
  125.   cursor = gdk_cursor_new_for_display (display, GDK_CROSSHAIR);
  126.   
  127.   if (gdk_pointer_grab (popup->window, FALSE,
  128.             GDK_BUTTON_RELEASE_MASK,
  129.             NULL,
  130.             cursor,
  131.             GDK_CURRENT_TIME) == GDK_GRAB_SUCCESS)
  132.     {
  133.       gboolean clicked = FALSE;
  134.       
  135.       g_signal_connect (popup, "button-release-event",
  136.             G_CALLBACK (button_release_event_cb), &clicked);
  137.       
  138.       /* Process events until clicked is set by button_release_event_cb.
  139.        * We pass in may_block=TRUE since we want to wait if there
  140.        * are no events currently.
  141.        */
  142.       while (!clicked)
  143.     g_main_context_iteration (NULL, TRUE);
  144.       
  145.       toplevel = find_toplevel_at_pointer (gdk_screen_get_display (screen));
  146.       if (toplevel == popup)
  147.     toplevel = NULL;
  148.     }
  149.       
  150.   gdk_cursor_unref (cursor);
  151.   gtk_widget_destroy (popup);
  152.   gdk_flush ();            /* Really release the grab */
  153.   
  154.   return toplevel;
  155. }
  156.  
  157. /* Prompts the user for a toplevel window to move, and then moves
  158.  * that window to the currently selected display
  159.  */
  160. static void
  161. query_change_display (ChangeDisplayInfo *info)
  162. {
  163.   GdkScreen *screen = gtk_widget_get_screen (info->window);
  164.   GtkWidget *toplevel;
  165.  
  166.   toplevel = query_for_toplevel (screen,
  167.                  "Please select the toplevel\n"
  168.                  "to move to the new screen");
  169.  
  170.   if (toplevel)
  171.     gtk_window_set_screen (GTK_WINDOW (toplevel), info->current_screen);
  172.   else
  173.     gdk_display_beep (gdk_screen_get_display (screen));
  174. }
  175.  
  176. /* Fills in the screen list based on the current display
  177.  */
  178. static void
  179. fill_screens (ChangeDisplayInfo *info)
  180. {
  181.   gtk_list_store_clear (GTK_LIST_STORE (info->screen_model));
  182.  
  183.   if (info->current_display)
  184.     {
  185.       gint n_screens = gdk_display_get_n_screens (info->current_display);
  186.       gint i;
  187.       
  188.       for (i = 0; i < n_screens; i++)
  189.     {
  190.       GdkScreen *screen = gdk_display_get_screen (info->current_display, i);
  191.       GtkTreeIter iter;
  192.       
  193.       gtk_list_store_append (GTK_LIST_STORE (info->screen_model), &iter);
  194.       gtk_list_store_set (GTK_LIST_STORE (info->screen_model), &iter,
  195.                   SCREEN_COLUMN_NUMBER, i,
  196.                   SCREEN_COLUMN_SCREEN, screen,
  197.                   -1);
  198.  
  199.       if (i == 0)
  200.         gtk_tree_selection_select_iter (info->screen_selection, &iter);
  201.     }
  202.     }
  203. }
  204.  
  205. /* Called when the user clicks on a button in our dialog or
  206.  * closes the dialog through the window manager. Unless the
  207.  * "Change" button was clicked, we destroy the dialog.
  208.  */
  209. static void
  210. response_cb (GtkDialog         *dialog,
  211.          gint               response_id,
  212.          ChangeDisplayInfo *info)
  213. {
  214.   if (response_id == GTK_RESPONSE_OK)
  215.     query_change_display (info);
  216.   else
  217.     gtk_widget_destroy (GTK_WIDGET (dialog));
  218. }
  219.  
  220. /* Called when the user clicks on "Open..." in the display
  221.  * frame. Prompts for a new display, and then opens a connection
  222.  * to that display.
  223.  */
  224. static void
  225. open_display_cb (GtkWidget         *button,
  226.          ChangeDisplayInfo *info)
  227. {
  228.   GtkWidget *dialog;
  229.   GtkWidget *display_entry;
  230.   GtkWidget *dialog_label;
  231.   gchar *new_screen_name = NULL;
  232.   GdkDisplay *result = NULL;
  233.   
  234.   dialog = gtk_dialog_new_with_buttons ("Open Display",
  235.                     GTK_WINDOW (info->window),
  236.                     GTK_DIALOG_MODAL,
  237.                     GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
  238.                     GTK_STOCK_OK, GTK_RESPONSE_OK,
  239.                     NULL);
  240.  
  241.   gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK);
  242.   display_entry = gtk_entry_new ();
  243.   gtk_entry_set_activates_default (GTK_ENTRY (display_entry), TRUE);
  244.   dialog_label =
  245.     gtk_label_new ("Please enter the name of\nthe new display\n");
  246.  
  247.   gtk_container_add (GTK_CONTAINER (GTK_DIALOG (dialog)->vbox), dialog_label);
  248.   gtk_container_add (GTK_CONTAINER (GTK_DIALOG (dialog)->vbox), display_entry);
  249.  
  250.   gtk_widget_grab_focus (display_entry);
  251.   gtk_widget_show_all (GTK_BIN (dialog)->child);
  252.   
  253.   while (!result)
  254.     {
  255.       gint response_id = gtk_dialog_run (GTK_DIALOG (dialog));
  256.       if (response_id != GTK_RESPONSE_OK)
  257.     break;
  258.       
  259.       new_screen_name = gtk_editable_get_chars (GTK_EDITABLE (display_entry),
  260.                         0, -1);
  261.  
  262.       if (strcmp (new_screen_name, "") != 0)
  263.     {
  264.       result = gdk_display_open (new_screen_name);
  265.       if (!result)
  266.         {
  267.           gchar *error_msg =
  268.         g_strdup_printf  ("Can't open display :\n\t%s\nplease try another one\n",
  269.                   new_screen_name);
  270.           gtk_label_set_text (GTK_LABEL (dialog_label), error_msg);
  271.           g_free (error_msg);
  272.         }
  273.  
  274.       g_free (new_screen_name);
  275.     }
  276.     }
  277.   
  278.   gtk_widget_destroy (dialog);
  279. }
  280.  
  281. /* Called when the user clicks on the "Close" button in the
  282.  * "Display" frame. Closes the selected display.
  283.  */
  284. static void
  285. close_display_cb (GtkWidget         *button,
  286.           ChangeDisplayInfo *info)
  287. {
  288.   if (info->current_display)
  289.     gdk_display_close (info->current_display);
  290. }
  291.  
  292. /* Called when the selected row in the display list changes.
  293.  * Updates info->current_display, then refills the list of
  294.  * screens.
  295.  */
  296. static void
  297. display_changed_cb (GtkTreeSelection  *selection,
  298.             ChangeDisplayInfo *info)
  299. {
  300.   GtkTreeModel *model;
  301.   GtkTreeIter iter;
  302.  
  303.   if (gtk_tree_selection_get_selected (selection, &model, &iter))
  304.     gtk_tree_model_get (model, &iter,
  305.             DISPLAY_COLUMN_DISPLAY, &info->current_display,
  306.             -1);
  307.   else
  308.     info->current_display = NULL;
  309.  
  310.   fill_screens (info);
  311. }
  312.  
  313. /* Called when the selected row in the sceen list changes.
  314.  * Updates info->current_screen.
  315.  */
  316. static void
  317. screen_changed_cb (GtkTreeSelection  *selection,
  318.            ChangeDisplayInfo *info)
  319. {
  320.   GtkTreeModel *model;
  321.   GtkTreeIter iter;
  322.  
  323.   if (gtk_tree_selection_get_selected (selection, &model, &iter))
  324.     gtk_tree_model_get (model, &iter,
  325.             SCREEN_COLUMN_SCREEN, &info->current_screen,
  326.             -1);
  327.   else
  328.     info->current_screen = NULL;
  329. }
  330.  
  331. /* This function is used both for creating the "Display" and
  332.  * "Screen" frames, since they have a similar structure. The
  333.  * caller hooks up the right context for the value returned
  334.  * in tree_view, and packs any relevant buttons into button_vbox.
  335.  */
  336. static void
  337. create_frame (ChangeDisplayInfo *info,
  338.           const char        *title,
  339.           GtkWidget        **frame,
  340.           GtkWidget        **tree_view,
  341.           GtkWidget        **button_vbox)
  342. {
  343.   GtkTreeSelection *selection;
  344.   GtkWidget *scrollwin;
  345.   GtkWidget *hbox;
  346.   
  347.   *frame = gtk_frame_new (title);
  348.  
  349.   hbox = gtk_hbox_new (FALSE, 8);
  350.   gtk_container_set_border_width (GTK_CONTAINER (hbox), 8);
  351.   gtk_container_add (GTK_CONTAINER (*frame), hbox);
  352.  
  353.   scrollwin = gtk_scrolled_window_new (NULL, NULL);
  354.   gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrollwin),
  355.                   GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
  356.   gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrollwin),
  357.                        GTK_SHADOW_IN);
  358.   gtk_box_pack_start (GTK_BOX (hbox), scrollwin, TRUE, TRUE, 0);
  359.  
  360.   *tree_view = gtk_tree_view_new ();
  361.   gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (*tree_view), FALSE);
  362.   gtk_container_add (GTK_CONTAINER (scrollwin), *tree_view);
  363.  
  364.   selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (*tree_view));
  365.   gtk_tree_selection_set_mode (selection, GTK_SELECTION_BROWSE);
  366.  
  367.   *button_vbox = gtk_vbox_new (FALSE, 5);
  368.   gtk_box_pack_start (GTK_BOX (hbox), *button_vbox, FALSE, FALSE, 0);
  369.  
  370.   if (!info->size_group)
  371.     info->size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
  372.   
  373.   gtk_size_group_add_widget (GTK_SIZE_GROUP (info->size_group), *button_vbox);
  374. }
  375.  
  376. /* If we have a stack of buttons, it often looks better if their contents
  377.  * are left-aligned, rather than centered. This function creates a button
  378.  * and left-aligns it contents.
  379.  */
  380. GtkWidget *
  381. left_align_button_new (const char *label)
  382. {
  383.   GtkWidget *button = gtk_button_new_with_mnemonic (label);
  384.   GtkWidget *child = gtk_bin_get_child (GTK_BIN (button));
  385.  
  386.   gtk_misc_set_alignment (GTK_MISC (child), 0., 0.5);
  387.  
  388.   return button;
  389. }
  390.  
  391. /* Creates the "Display" frame in the main window.
  392.  */
  393. GtkWidget *
  394. create_display_frame (ChangeDisplayInfo *info)
  395. {
  396.   GtkWidget *frame;
  397.   GtkWidget *tree_view;
  398.   GtkWidget *button_vbox;
  399.   GtkTreeViewColumn *column;
  400.   GtkTreeSelection *selection;
  401.   GtkWidget *button;
  402.  
  403.   create_frame (info, "Display", &frame, &tree_view, &button_vbox);
  404.  
  405.   button = left_align_button_new ("_Open...");
  406.   g_signal_connect (button, "clicked",  G_CALLBACK (open_display_cb), info);
  407.   gtk_box_pack_start (GTK_BOX (button_vbox), button, FALSE, FALSE, 0);
  408.   
  409.   button = left_align_button_new ("_Close");
  410.   g_signal_connect (button, "clicked",  G_CALLBACK (close_display_cb), info);
  411.   gtk_box_pack_start (GTK_BOX (button_vbox), button, FALSE, FALSE, 0);
  412.  
  413.   info->display_model = (GtkTreeModel *)gtk_list_store_new (DISPLAY_NUM_COLUMNS,
  414.                                 G_TYPE_STRING,
  415.                                 GDK_TYPE_DISPLAY);
  416.  
  417.   gtk_tree_view_set_model (GTK_TREE_VIEW (tree_view), info->display_model);
  418.  
  419.   column = gtk_tree_view_column_new_with_attributes ("Name",
  420.                              gtk_cell_renderer_text_new (),
  421.                              "text", DISPLAY_COLUMN_NAME,
  422.                              NULL);
  423.   gtk_tree_view_append_column (GTK_TREE_VIEW (tree_view), column);
  424.  
  425.   selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (tree_view));
  426.   g_signal_connect (selection, "changed",
  427.             G_CALLBACK (display_changed_cb), info);
  428.  
  429.   return frame;
  430. }
  431.  
  432. /* Creates the "Screen" frame in the main window.
  433.  */
  434. GtkWidget *
  435. create_screen_frame (ChangeDisplayInfo *info)
  436. {
  437.   GtkWidget *frame;
  438.   GtkWidget *tree_view;
  439.   GtkWidget *button_vbox;
  440.   GtkTreeViewColumn *column;
  441.  
  442.   create_frame (info, "Screen", &frame, &tree_view, &button_vbox);
  443.  
  444.   info->screen_model = (GtkTreeModel *)gtk_list_store_new (SCREEN_NUM_COLUMNS,
  445.                                G_TYPE_INT,
  446.                                GDK_TYPE_SCREEN);
  447.  
  448.   gtk_tree_view_set_model (GTK_TREE_VIEW (tree_view), info->screen_model);
  449.  
  450.   column = gtk_tree_view_column_new_with_attributes ("Number",
  451.                              gtk_cell_renderer_text_new (),
  452.                              "text", SCREEN_COLUMN_NUMBER,
  453.                              NULL);
  454.   gtk_tree_view_append_column (GTK_TREE_VIEW (tree_view), column);
  455.  
  456.   info->screen_selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (tree_view));
  457.   g_signal_connect (info->screen_selection, "changed",
  458.             G_CALLBACK (screen_changed_cb), info);
  459.  
  460.   return frame;
  461. }
  462.  
  463. /* Called when one of the currently open displays is closed.
  464.  * Remove it from our list of displays.
  465.  */
  466. static void
  467. display_closed_cb (GdkDisplay        *display,
  468.            gboolean           is_error,
  469.            ChangeDisplayInfo *info)
  470. {
  471.   GtkTreeIter iter;
  472.   gboolean valid;
  473.  
  474.   for (valid = gtk_tree_model_get_iter_first (info->display_model, &iter);
  475.        valid;
  476.        valid = gtk_tree_model_iter_next (info->display_model, &iter))
  477.     {
  478.       GdkDisplay *tmp_display;
  479.       
  480.       gtk_tree_model_get (info->display_model, &iter,
  481.               DISPLAY_COLUMN_DISPLAY, &tmp_display,
  482.               -1);
  483.       if (tmp_display == display)
  484.     {
  485.       gtk_list_store_remove (GTK_LIST_STORE (info->display_model), &iter);
  486.       break;
  487.     }
  488.     }
  489. }
  490.  
  491. /* Adds a new display to our list of displays, and connects
  492.  * to the "closed" signal so that we can remove it from the
  493.  * list of displays again.
  494.  */
  495. static void
  496. add_display (ChangeDisplayInfo *info,
  497.          GdkDisplay        *display)
  498. {
  499.   const gchar *name = gdk_display_get_name (display);
  500.   GtkTreeIter iter;
  501.   
  502.   gtk_list_store_append (GTK_LIST_STORE (info->display_model), &iter);
  503.   gtk_list_store_set (GTK_LIST_STORE (info->display_model), &iter,
  504.               DISPLAY_COLUMN_NAME, name,
  505.               DISPLAY_COLUMN_DISPLAY, display,
  506.               -1);
  507.  
  508.   g_signal_connect (display, "closed",
  509.             G_CALLBACK (display_closed_cb), info); 
  510. }
  511.  
  512. /* Called when a new display is opened
  513.  */
  514. static void
  515. display_opened_cb (GdkDisplayManager *manager,
  516.            GdkDisplay        *display,
  517.            ChangeDisplayInfo *info)
  518. {
  519.   add_display (info, display);
  520. }
  521.  
  522. /* Adds all currently open displays to our list of displays,
  523.  * and set up a signal connection so that we'll be notified
  524.  * when displays are opened in the future as well.
  525.  */
  526. static void
  527. initialize_displays (ChangeDisplayInfo *info)
  528. {
  529.   GdkDisplayManager *manager = gdk_display_manager_get ();
  530.   GSList *displays = gdk_display_manager_list_displays (manager);
  531.   GSList *tmp_list;
  532.  
  533.   for (tmp_list = displays; tmp_list; tmp_list = tmp_list->next)
  534.     add_display (info, tmp_list->data);
  535.  
  536.   g_slist_free (tmp_list);
  537.  
  538.   g_signal_connect (manager, "display_opened",
  539.             G_CALLBACK (display_opened_cb), info);
  540. }
  541.  
  542. /* Cleans up when the toplevel is destroyed; we remove the
  543.  * connections we use to track currently open displays, then
  544.  * free the ChangeDisplayInfo structure.
  545.  */
  546. static void
  547. destroy_info (ChangeDisplayInfo *info)
  548. {
  549.   GdkDisplayManager *manager = gdk_display_manager_get ();
  550.   GSList *displays = gdk_display_manager_list_displays (manager);
  551.   GSList *tmp_list;
  552.  
  553.   g_signal_handlers_disconnect_by_func (manager,
  554.                     display_opened_cb,
  555.                     info);
  556.  
  557.   for (tmp_list = displays; tmp_list; tmp_list = tmp_list->next)
  558.     g_signal_handlers_disconnect_by_func (tmp_list->data,
  559.                       display_closed_cb,
  560.                       info);
  561.   
  562.   g_slist_free (tmp_list);
  563.  
  564.   g_object_unref (info->size_group);
  565.   g_free (info);
  566. }
  567.  
  568. static void
  569. destroy_cb (GtkObject          *object,
  570.         ChangeDisplayInfo **info)
  571. {
  572.   destroy_info (*info);
  573.   *info = NULL;
  574. }
  575.  
  576. /* Main entry point. If the dialog for this demo doesn't yet exist, creates
  577.  * it. Otherwise, destroys it.
  578.  */
  579. GtkWidget *
  580. do_changedisplay (GtkWidget *do_widget)
  581. {
  582.   static ChangeDisplayInfo *info = NULL;
  583.  
  584.   if (!info)
  585.     {
  586.       GtkWidget *vbox;
  587.       GtkWidget *frame;
  588.  
  589.       info = g_new0 (ChangeDisplayInfo, 1);
  590.  
  591.       info->window = gtk_dialog_new_with_buttons ("Change Screen or display",
  592.                         GTK_WINDOW (do_widget), 
  593.                         GTK_DIALOG_NO_SEPARATOR,
  594.                         GTK_STOCK_CLOSE,  GTK_RESPONSE_CLOSE,
  595.                         "Change",         GTK_RESPONSE_OK,
  596.                         NULL);
  597.  
  598.       gtk_window_set_default_size (GTK_WINDOW (info->window), 300, 400);
  599.  
  600.       g_signal_connect (info->window, "response",
  601.             G_CALLBACK (response_cb), info);
  602.       g_signal_connect (info->window, "destroy",
  603.             G_CALLBACK (destroy_cb), &info);
  604.  
  605.       vbox = gtk_vbox_new (FALSE, 5);
  606.       gtk_container_set_border_width (GTK_CONTAINER (vbox), 8);
  607.     
  608.       gtk_box_pack_start (GTK_BOX (GTK_DIALOG (info->window)->vbox), vbox,
  609.               TRUE, TRUE, 0);
  610.  
  611.       frame = create_display_frame (info);
  612.       gtk_box_pack_start (GTK_BOX (vbox), frame, TRUE, TRUE, 0);
  613.       
  614.       frame = create_screen_frame (info);
  615.       gtk_box_pack_start (GTK_BOX (vbox), frame, TRUE, TRUE, 0);
  616.  
  617.       initialize_displays (info);
  618.  
  619.       gtk_widget_show_all (info->window);
  620.       return info->window;
  621.     }
  622.   else
  623.     {
  624.       gtk_widget_destroy (info->window);
  625.       return NULL;
  626.     }
  627. }
  628.